#include <cstring>
#include <iostream>

#include "VulkanNode.h"
#include "MemoryTool.h"


namespace namespace_easy_car_ui
{

VulkanNode::VulkanNode(
    VkPhysicalDevice physicalDevice,
    VkDevice device,
    VkCommandPool commandPool,
    VkQueue queue):
        m_physicalDevice(physicalDevice),
        m_device(device),
        m_commandPool(commandPool),
        m_queue(queue)
{

    
}

VulkanNode::~VulkanNode()
{
    vkFreeMemory(m_device, m_vertexBufferMemory, nullptr);
    vkDestroyBuffer(m_device, m_vertexBuffer, nullptr);

    vkFreeMemory(m_device, m_indexBufferMemory, nullptr);
    vkDestroyBuffer(m_device, m_indexBuffer, nullptr);
}

void VulkanNode::CreateIndexAndVertexBuffer(const Node& node)
{
    {
        VkDeviceSize bufferSize = sizeof(node.m_vertes[0]) * node.m_vertes.size();

        VkBuffer stagingBuffer;
        VkDeviceMemory stagingBufferMemory;
        MemoryTool::CreateBuffer(
            m_physicalDevice,
            m_device,
            bufferSize,
            VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
            stagingBuffer,
            stagingBufferMemory);

        void* data;
        vkMapMemory(m_device, stagingBufferMemory, 0, bufferSize, 0, &data);
        memcpy(data, node.m_vertes.data(), (size_t) bufferSize);
        vkUnmapMemory(m_device, stagingBufferMemory);

        MemoryTool::CreateBuffer(
            m_physicalDevice,
            m_device,
            bufferSize,
            VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
            m_vertexBuffer,
            m_vertexBufferMemory);

        MemoryTool::CopyBuffer(
            m_device,
            m_commandPool,
            m_queue,
            stagingBuffer,
            m_vertexBuffer,
            bufferSize);

        vkDestroyBuffer(m_device, stagingBuffer, nullptr);
        vkFreeMemory(m_device, stagingBufferMemory, nullptr);
    }

    {
        m_numIndics =  static_cast<uint32_t>(node.m_indices.size());
        VkDeviceSize bufferSize = sizeof(node.m_indices[0]) * node.m_indices.size();

        VkBuffer stagingBuffer;
        VkDeviceMemory stagingBufferMemory;
        MemoryTool::CreateBuffer(
            m_physicalDevice,
            m_device,
            bufferSize,
            VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
            stagingBuffer,
            stagingBufferMemory);

        void* data;
        vkMapMemory(m_device, stagingBufferMemory, 0, bufferSize, 0, &data);
        memcpy(data, node.m_indices.data(), (size_t) bufferSize);
        vkUnmapMemory(m_device, stagingBufferMemory);

        MemoryTool::CreateBuffer(
            m_physicalDevice,
            m_device,bufferSize,
            VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
            m_indexBuffer,
            m_indexBufferMemory);

        MemoryTool::CopyBuffer(
            m_device,
            m_commandPool,
            m_queue,
            stagingBuffer,
            m_indexBuffer,
            bufferSize);

        vkDestroyBuffer(m_device, stagingBuffer, nullptr);
        vkFreeMemory(m_device, stagingBufferMemory, nullptr);
    }
}

VkBuffer VulkanNode::GetVertexBuffer()
{
    return m_vertexBuffer;
}

VkBuffer VulkanNode::GetIndexBuffer()
{
    return m_indexBuffer;
}

uint32_t VulkanNode::GetNumIndics()
{
    return m_numIndics;
}


} /*namespace_easy_car_ui*/